package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.AutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description TODO
 * @Author bo.li
 * @Date 2022/11/11 10:44
 * @Version 1.0
 */
@Service
@Slf4j
public class AutoScanServiceImpl implements AutoScanService {

    @Resource
    private WmNewsMapper newsMapper;

    @Autowired
    private GreenTextScan textScan;

    @Autowired
    private GreenImageScan imageScan;

    @Autowired
    private FileStorageService storageService;
    @Autowired
    private WmUserMapper userMapper;

    @Resource
    private WmChannelMapper channelMapper;

    @Autowired
    private IArticleClient articleClient;

    @Resource
    private WmSensitiveMapper sensitiveMapper;
    @Autowired
    private Tess4jClient tess4jClient;

    public static final int SUCCESS_CODE = 200;

    @Async
    @Override
    public void scan(Integer newId) {
        log.info("开始审核文章,文章ID：{}",newId);
        WmNews wmNews = newsMapper.selectById(newId);
        if(wmNews == null){
            log.info("文章ID不存在，id:{}",newId);
            return;
        }
        if(wmNews.getStatus() != WmNews.Status.SUBMIT.getCode()){
            log.info("文章状态不是待审核");
            return;
        }

        Map<String,Object> textImageMap = getTextAndImage(wmNews);
        //敏感词
        boolean flag = sensitiveCheck(textImageMap.get("text") + "",wmNews);
        if(!flag){
            log.info("文本内容含敏感词,文章ID:{}",newId);
            return;
        }
        flag = scanText(wmNews, textImageMap.get("text") + "");
        if(!flag){
            log.info("文本内容审核不通过,文章ID:{}",newId);
            return;
        }
        flag = scanImage((List<String>) textImageMap.get("image"),wmNews);
        if(!flag){
            log.info("图片审核不通过,文章ID:{}",newId);
            return;
        }
        wmNews.setStatus(WmNews.Status.SUCCESS.getCode());
        wmNews.setReason("审核通过");
        newsMapper.updateById(wmNews);

        ResponseResult result = saveArticle(wmNews);
        if(result.getCode() != SUCCESS_CODE)       {
            log.error("保存文章失败,返回信息：{}",JSON.toJSONString(result));
            return;
        }

        wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
        wmNews.setReason("发布成功");
        wmNews.setArticleId((long)result.getData());
        newsMapper.updateById(wmNews);
        log.info("文章审核完成,文章ID：{}",newId);
    }


    /**
     *
     * 敏感词审核
     * @param content
     * @param wmNews
     * @return
     */
    private boolean sensitiveCheck(String content,WmNews wmNews){
        List<WmSensitive> wmSensitives = sensitiveMapper.selectList(Wrappers.emptyWrapper());
        if(CollectionUtils.isEmpty(wmSensitives)){
            return true;
        }
        //初始化
        SensitiveWordUtil.initMap(wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList()));
        Map<String, Integer> matchWords = SensitiveWordUtil.matchWords(content);
        if(CollectionUtils.isEmpty(matchWords)){
            return true;
        }
        wmNews.setStatus(WmNews.Status.FAIL.getCode());
        wmNews.setReason("包含敏感词：" + matchWords);
        newsMapper.updateById(wmNews);

        return false;
    }



    /**
     * 保存文章
     *
     * @param wmNews
     * @return
     */
    private ResponseResult saveArticle(WmNews wmNews){
        ArticleDto dto = new ArticleDto();
        BeanUtils.copyProperties(wmNews,dto);
        dto.setAuthorId(wmNews.getUserId());
        dto.setId(null);
        WmUser user = userMapper.selectById(wmNews.getUserId());
        dto.setAuthorName(user == null ? "" : user.getName());
        //布局
        dto.setLayout(wmNews.getType());

        WmChannel wmChannel = channelMapper.selectById(wmNews.getChannelId());
        dto.setChannelName(wmChannel == null ? "" : wmChannel.getName());
        if(wmNews.getArticleId() != null){
            dto.setId(wmNews.getArticleId());
        }
        return articleClient.saveArticle(dto);
    }

    /**
     * 图片检测
     *
     * @param pics
     * @param news
     * @return
     */
    private boolean scanImage(List<String> pics, WmNews news){
        if(CollectionUtils.isEmpty(pics)){
            return true;
        }
        boolean flag = true;
        List<byte[]> scanByteList = new ArrayList<>();
        for(String image : pics) {
            byte[] imageByte = storageService.downLoadFile(image);

            try{
                String content = tess4jClient.doOCR(ImageIO.read(new ByteArrayInputStream(imageByte)));
                flag = sensitiveCheck(content, news);
                if(!flag){
                    return false;
                }
            }catch (Exception e){
                log.error("图片识别异常",e);
            }
            scanByteList.add(imageByte);
        }
        try {
            Map map = imageScan.imageScan(scanByteList);
            String suggestion = map.get("suggestion") + "";
            String label = map.get("label") + "";
            if("block".equals(suggestion)){
                news.setStatus(WmNews.Status.FAIL.getCode());
                news.setReason(label);
                newsMapper.updateById(news);
                flag = false;
            }else if("review".equals(suggestion)){
                news.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
                news.setReason("转人工审核");
                newsMapper.updateById(news);
                flag = false;
            }
        }catch (Exception e){
            log.error("图片扫描失败",e);
            return flag;
        }

        return flag;
    }

    /**
     * 文本内容安全检测
     *
     * @param news
     * @param content
     * @return
     */
    private boolean scanText(WmNews news, String content){
        boolean flag = true;
        try {
            Map map = textScan.greeTextScan(content);
            String suggestion = map.get("suggestion") + "";
            String label = map.get("label") + "";
            if("block".equals(suggestion)){
                news.setStatus(WmNews.Status.FAIL.getCode());
                news.setReason(label);
                newsMapper.updateById(news);
                flag = false;
            }else if("review".equals(suggestion)){
                news.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
                news.setReason("转人工审核");
                newsMapper.updateById(news);
                flag = false;
            }
        }catch (Exception e){
            log.error("文本扫描异常",e);
            return flag;
        }
        return flag;
    }


    /**
     * 获取文章文本信息和图片
     * 文本：包含正文和标题
     * 图片：正文图片和封面图片
     *
     * @param wmNews
     * @return
     */
    private Map<String,Object> getTextAndImage(WmNews wmNews){
        Map<String,Object> textImageMap = new HashMap<>();
        StringBuilder textBuilder = new StringBuilder();
        List<String> pics = new ArrayList<>();
        List<Map> mapList = JSON.parseArray(wmNews.getContent(),Map.class);
        for(Map map : mapList){
            String type = map.get("type") +"";
            String value = map.get("value") + "";
            if("text".equals(type)){
                textBuilder.append(value);
            }else if("image".equals(type)){
                pics.add(value);
            }
        }

        textBuilder.append("-").append(wmNews.getTitle());
        if(!StringUtils.isEmpty(wmNews.getImages())){
            String[] coverImages = StringUtils.commaDelimitedListToStringArray(wmNews.getImages());
            pics.addAll(Arrays.asList(coverImages));
        }
        textImageMap.put("text",textBuilder.toString());
        textImageMap.put("image",pics);

        return textImageMap;
    }
}